package cn.spdb.harrier.common.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

public class ClassUtils {

	private static final String DOT = ".";
	private static final String ZIP_SLASH = "/";
	private static final String CLASS_EXT = ".class";
	private static final String JAR_FILE_EXT = ".jar";
	private static final CharSequence BLACK = "";

	/**
	 * 获取所有class
	 * 
	 * @return
	 */
	private static String[] getClassPathArray() {
		return System.getProperty("java.class.path").concat(System.getProperty("path.separator"))
				.concat(System.getProperty("java.home")).split(System.getProperty("path.separator"));
	}

	public static List<Class<?>> scanPackage(Package packagea, ClassFilter classFilter) {
		return scanPackage(packagea.getName(), classFilter);
	}


/**
 * 扫描指定包路径下的所有类，并可选地通过 ClassFilter 过滤
 *
 * @param packageName 要扫描的包名
 * @param classFilter 用于过滤类的条件，如果为 null 则不过滤
 * @return 返回符合条件的类列表
 */
public static List<Class<?>> scanPackage(String packageName, ClassFilter classFilter) {
    // 创建一个空列表，用于存储扫描到的符合条件的类
    final List<Class<?>> classes = new ArrayList<Class<?>>();

    // 如果包名不为空字符串，则确保包名以 "." 结尾，便于后续匹配
    if (!StringUtils.isBlank(packageName)) {
        packageName = packageName.lastIndexOf(DOT) != packageName.length() - 1 ? packageName + DOT : packageName;
    }

    // 获取系统类路径（classpath），并按系统分隔符拆分成数组
    String[] classPaths = System.getProperty("java.class.path").split(System.getProperty("path.separator"));

    // 遍历每个类路径，将其转换为 File 对象后调用 fillClasses 方法填充类信息
    for (String classPath : classPaths) {
        fillClasses(new File(classPath), packageName, classFilter, classes);
    }

    // 返回最终扫描到的所有符合条件的类
    return classes;
}


	private static void fillClasses(File file, String packageName, ClassFilter classFilter, List<Class<?>> classes) {
		if (file.isDirectory()) {
			processDirectory(file, packageName, classFilter, classes);
		} else if (file.getName().endsWith(CLASS_EXT)) {
			processClassFile(file, packageName, classFilter, classes);
		} else if (file.getName().endsWith(JAR_FILE_EXT)) {
			processJarFile(file, packageName, classFilter, classes);
		}
	}

	private static void processJarFile(File file, String packageName, ClassFilter classFilter, List<Class<?>> classes) {

		try {
			for (ZipEntry entry : Collections.list(new ZipFile(file).entries())) {
				if (entry.getName().endsWith(CLASS_EXT)) {
					final String className = entry.getName().replace(ZIP_SLASH, DOT).replace(CLASS_EXT, BLACK);
					fillClass(className, packageName, classFilter, classes);
				}
			}
		} catch (ZipException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private static void processClassFile(File file, String packageName, ClassFilter classFilter,
			List<Class<?>> classes) {
		final String filePathWithDot = file.getAbsolutePath().replace(File.separator, DOT);
		int subIndex = -1;
		if ((subIndex = filePathWithDot.indexOf(packageName)) != -1) {
			final String calssName = filePathWithDot.substring(subIndex).replace(CLASS_EXT, BLACK);
			fillClass(calssName, packageName, classFilter, classes);
		}
	}

/**
 * 将符合包名条件的类名转换为 Class 对象，并根据 ClassFilter 过滤后添加到类列表中
 *
 * @param calssName     类名（注意：拼写错误 "calssName" 应为 "className"）
 * @param packageName   包名，用于匹配类是否在指定包下
 * @param classFilter   类过滤器，用于进一步筛选类
 * @param classes       存储符合条件的 Class 对象的列表
 */
private static void fillClass(String calssName, String packageName, ClassFilter classFilter,
        List<Class<?>> classes) {
    // 检查类名是否以指定包名开头
    if (calssName.indexOf(packageName) == 0) {
        try {
            // 使用 ClassUtils 的类加载器加载类
            final Class<?> clazz = Class.forName(calssName, false, ClassUtils.class.getClassLoader());

            // 如果 classFilter 为 null 或者通过了过滤条件，则将该类加入结果列表
            if (checkClassFilter(classFilter, clazz)) {
                classes.add(clazz);
            }
        } catch (ClassNotFoundException e) {
            // 类未找到时打印异常信息
            e.printStackTrace();
        }
    }
}


	private static boolean checkClassFilter(ClassFilter classFilter, Class<?> clazz) {
		return classFilter == null || classFilter.actionFilter(clazz);
	}

	/**
	 * 文件夹处理
	 * 
	 * @param dir
	 * @param packageName
	 * @param classFilter
	 * @param classes
	 */
	private static void processDirectory(File dir, String packageName, ClassFilter classFilter,
			List<Class<?>> classes) {
		for (File file : dir.listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				return pathname.isDirectory() || pathname.getName().endsWith(CLASS_EXT)
						|| pathname.getName().endsWith(CLASS_EXT);
			}
		})) {
			fillClasses(file, packageName, classFilter, classes);
		}
	}

	public interface ClassFilter {
		public boolean actionFilter(Class<?> clazz);
	}

}
